package com.yss.sofa.report.engine.core;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import com.yss.sofa.report.engine.Const;
import com.yss.sofa.report.engine.cell.visible.result.NormalResultCell;
import com.yss.sofa.report.engine.cell.visible.result.ResultCell;


public class Matrix implements Serializable{
	private static final long serialVersionUID = -8996255197904208001L;
	private ResultCell[][] data=new ResultCell[0][0];
	private int rowCount=0;
	private int colCount=0;
	public void print(){
		System.out.println("++++++++++++++++++++++++++++++++++++++++++");
		for(int r=0;r<rowCount;r++){
			for(int c=0;c<colCount;c++){
				ResultCell cell=data[r][c];
				String v=(cell==null)?null:(cell.getValue()==null?null:cell.getValue().replaceAll("\n", ""));
				System.out.print(v);
				System.out.print("\t");
			}
			System.out.print("\n");
		}
		System.out.println("++++++++++++++++++++++++++++++++++++++++++");
	}
	private void grow(int rowInc,int colInc){
		if(rowInc<=0 && colInc<=0){
			return;
		}
		ResultCell[][] new_data=new ResultCell[rowCount+rowInc][colCount+colInc];
		for(int r=0;r<rowCount;r++){
			for(int c=0;c<colCount;c++){
				new_data[r][c]=data[r][c];
				data[r][c]=null;
			}
		}
		data=new_data;
		rowCount+=rowInc;
		colCount+=colInc;
	}	
	//不再允许单元格覆盖，因为落到合并区的话，无法产生合理的二次拆分规则
	private boolean isOverlap(Block block){
		int rbegin=block.top;
		int rend=block.top+block.rowCount-1;
		int cbegin=block.left;
		int cend=block.left+block.colCount-1;
		if(rbegin>=rowCount) return false;
		if(cbegin>=colCount) return false;
		int minRow=(rend<rowCount)?rend:(rowCount-1);
		int minCol=(cend<colCount)?cend:(colCount-1);
		for(int r=rbegin;r<=minRow;r++){
			for(int c=cbegin;c<=minCol;c++){
				if(data[r][c]!=null && block.data[r-block.top][c-block.left]!=null){
					return true;
				}
			}
		}
		return false;
	}
	public void set(Block block){
		//block.print();
		switch (block.move) {
		case Const.CELL_MOVE_INFER:
		case Const.CELL_MOVE_ABS:{
			if(isOverlap(block)){
				//不再允许单元格覆盖，因为落到合并区的话，无法产生合理的二次拆分规则
				return;
			} else {
				break;
			}
		}
		case Const.CELL_MOVE_RIGHT:{
			int realCol=-1;
			int left=block.left;
			for(int c=left;c<colCount;c++){
				block.left=c;
				if(!isOverlap(block)){
					realCol=c;
					break;
				}
			}
			if(realCol<0){
				realCol=colCount;
			}
			block.left=realCol;
			break;
		}
		case Const.CELL_MOVE_BOTTOM:{
			int realRow=-1;
			int top=block.top;
			for(int r=top;r<rowCount;r++){
				block.top=r;
				if(!isOverlap(block)){
					realRow=r;
					break;
				}
			}
			if(realRow<0){
				realRow=rowCount;
			}
			block.top=realRow;
			break;
		}
		default:
		}
		int rowInc=(block.getBottom()>=rowCount)?(block.getBottom()-rowCount+1):0;
		int colInc=(block.getRight()>=colCount)?(block.getRight()-colCount+1):0;
		grow(rowInc, colInc);
		Set<ResultCell> cells=new HashSet<ResultCell>();
		for(int r=0;r<block.rowCount;r++){
			for(int c=0;c<block.colCount;c++){
				ResultCell cell=block.data[r][c];
				if(cell==null){
					continue;
				}
				if(!cells.contains(cell)){
					//神奇的转换坐标，合并单元格是一个对象，别多次转换！
					int rbegin=cell.getRbegin();
					int rend=cell.getRend();
					int cbegin=cell.getCbegin();
					int cend=cell.getCend();
					cell.setRbegin(rbegin+block.top);
					cell.setRend(rend+block.top);
					cell.setCbegin(cbegin+block.left);
					cell.setCend(cend+block.left);
					cells.add(cell);
				}
				//print();
				data[r+block.top][c+block.left]=block.data[r][c];
				//print();
			}
		}
		cells.clear();
		//print();
	}
	public int getRowCount(){
		return rowCount;
	}
	public int getColCount(){
		return colCount;
	}
	public void setRowCount(int rowCount) {
		this.rowCount = rowCount;
	}
	public void setColCount(int colCount) {
		this.colCount = colCount;
	}
	public ResultCell get(int row,int col){
		return data[row][col];
	}
	public boolean isEmpty(){
		return this.data.length==0;
	}
	private void doHorizontalForceMerge(ResultCell cell){
		int rbegin=cell.getRbegin();
		int rend=cell.getRend();
		int cbegin=cell.getCbegin();
		int cend=cell.getCend();
		int begin=cbegin;
		int end=cend;
		left:for(int c=cbegin-1;c>=0;c--){
			for(int r=rbegin;r<=rend;r++){
				ResultCell rc=data[r][c];
				if((rc==null) || ((rc.getDataType()!=Const.CELL_DATA_TYPE_IMG) && (StringUtils.isEmpty(rc.getValue())) && (rc.getRbegin()>=rbegin) && (rc.getRend()<=rend))){
					//
				} else {
					break left;
				}
			}
			begin--;
		}
		right:for(int c=cend+1;c<colCount;c++){
			for(int r=rbegin;r<=rend;r++){
				ResultCell rc=data[r][c];
				if((rc==null) || ((rc.getDataType()!=Const.CELL_DATA_TYPE_IMG) && (StringUtils.isEmpty(rc.getValue())) && (rc.getRbegin()>=rbegin) && (rc.getRend()<=rend))){
					//
				} else {
					break right;
				}
			}
			end++;
		}
		cell.setCbegin(begin);
		cell.setCend(end);
		for(int c=begin;c<=end;c++){
			for(int r=rbegin;r<=rend;r++){
				data[r][c]=cell;
			}
		}
	}
	public void doVerticalForceMerge(ResultCell cell){
		int rbegin=cell.getRbegin();
		int rend=cell.getRend();
		int cbegin=cell.getCbegin();
		int cend=cell.getCend();
		int begin=rbegin;
		int end=rend;
		top:for(int r=rbegin-1;r>=0;r--){
			for(int c=cbegin;c<=cend;c++){
				ResultCell rc=data[r][c];
				if((rc==null) || ((rc.getDataType()!=Const.CELL_DATA_TYPE_IMG) && (StringUtils.isEmpty(rc.getValue())) && (rc.getCbegin()>=cbegin) && (rc.getCend()<=cend))){
					//
				} else {
					break top;
				}
			}
			begin--;
		}
		bottom:for(int r=rend+1;r<rowCount;r++){
			for(int c=cbegin;c<=cend;c++){
				ResultCell rc=data[r][c];
				if((rc==null) || ((rc.getDataType()!=Const.CELL_DATA_TYPE_IMG) && (StringUtils.isEmpty(rc.getValue())) && (rc.getCbegin()>=cbegin) && (rc.getCend()<=cend))){
					//
				} else {
					break bottom;
				}
			}
			end++;
		}
		cell.setRbegin(begin);
		cell.setRend(end);
		for(int r=begin;r<=end;r++){
			for(int c=cbegin;c<=cend;c++){
				data[r][c]=cell;
			}
		}
	}
	public void doForceMerge(){
		Set<ResultCell> cells=new HashSet<ResultCell>();
		for(int r=0;r<rowCount;r++){
			for(int c=0;c<colCount;c++){
				ResultCell cell=data[r][c];
				if((cell==null) || cells.contains(cell)){
					continue;
				}
				cells.add(cell);
				if(cell.needForceMerge()){
					switch (cell.getForceMergeTo()) {
						case FORCE_MERGE_TO_H:{
							doHorizontalForceMerge(cell);
							break;
						}
						case FORCE_MERGE_TO_V:{
							doVerticalForceMerge(cell);
							break;
						}
						default:
							break;
					}
				}
			}
		}
		cells.clear();
	}
	public void pack(List<Entry<String, Integer>> dataSetsRows,Map<String,Integer> formulaDataSetNumMap){
		int newRowCount=rowCount;
		int newColCount=colCount;
		row:for(int r=rowCount-1;r>=0;r--){
			for(int c=colCount-1;c>=0;c--){
				if(data[r][c]!=null){
					break row;
				}
			}
			newRowCount--;
		}
		col:for(int c=colCount-1;c>=0;c--){
			for(int r=rowCount-1;r>=0;r--){
				if(data[r][c]!=null){
					break col;
				}
			}
			newColCount--;
		}		
		ResultCell[][] newData=new ResultCell[newRowCount][newColCount];
		for(int r=0;r<newRowCount;r++){
			for(int c=0;c<newColCount;c++){
//				if(formulaDataSetNumMap.size()>0
//					&& data[r][c] instanceof NormalResultCell 
//					&& StringUtils.isNotBlank(data[r][c].getValue()) 
////					&& data[r][c].getValue().startsWith("=") 数据处理有修改，没有等号了
//					&& data[r][c].getValue().endsWith(")")){     //公式中的dataset单元格信息进行调整, 对公式的支持有限，扩展需要修改此处替换逻辑
//					//公式内容=SUM(E12:E${ROW-4})  r=19  c=4        
//					//公式内容=SUM(E22:E${ROW-4})  r=32  c=4
//					//单元格漂移=orginrow=12  newrow=12            
//					//单元格漂移=originrow=22 newrow=25       
//					String originForumlaValue = data[r][c].getValue();
//					String newFormulaValue = getReplacedFormula(originForumlaValue,dataSetsRows,formulaDataSetNumMap);
//					//((NormalResultCell)data[r][c]).setValue(newFormulaValue);
//				}
				
				
				newData[r][c]=data[r][c];
				data[r][c]=null;
			}
		}
		data=newData;
		rowCount=newRowCount;
		colCount=newColCount;
	}

	private static String getReplacedFormula(String formula,List<Entry<String, Integer>> dataSetsRows,Map<String,Integer> formulaDataSetNumMap){
		String middleFomula = fillWithStar(formula,"=.+?\\(");
		middleFomula=fillWithStar(middleFomula,"\\$\\{ROW.*\\}");
		middleFomula=fillWithStar(middleFomula,"\\$\\{COL.*\\}");
		middleFomula=fillWithStar(middleFomula,"[+*-/:]");
		middleFomula=fillWithStar(middleFomula,"[^0-9]");
		String newFormula = replaceFomulaRowNum(formula,middleFomula,dataSetsRows,formulaDataSetNumMap);
		return newFormula;
	}

	private static String replaceFomulaRowNum(String originStr ,String middleStr,List<Entry<String, Integer>> dataSetsRows,Map<String,Integer> formulaDataSetNumMap){
		int begin=0;
		int end=0;
		boolean previousIsNum=false;
		StringBuffer newStr = new StringBuffer();
		int index = 0;
		for(int i=0;i<originStr.length();i++) {
			if (middleStr.substring(i, i + 1).equals("*")) {  //当前是*
				if (previousIsNum) { //上一个是数字
					int originRowNum = Integer.parseInt(originStr.substring(begin, end));
					int offset=0;
					for(int j=0;j<dataSetsRows.size();j++){
						if(originRowNum>(dataSetsRows.get(j).getValue()+1)){
							offset+=(formulaDataSetNumMap.get(dataSetsRows.get(j).getKey())-1);
						}else{
							break;
						}
					}
					int newRowNum=originRowNum+offset;
					newStr.append(newRowNum);
					begin = end++;
					index++;
				} else {    //上一个是*
					end++;
				}
				previousIsNum = false;
			} else {         //当前是数字
				if (previousIsNum) { //上一个是数字
					end++;
				} else {    //上一个是*
					String stringStr = originStr.substring(begin, end);
					newStr.append(stringStr);
					begin = end++;
				}
				previousIsNum = true;
			}
		}
		newStr.append(originStr.substring(begin, end));

		return newStr.toString();
	}

	//公式中如果含义"~"处理会发生错误
	private static String fillWithStar(String originStr,String regix){
		int originLength=originStr.length();
		originStr = originStr.replaceAll(regix,"~");
		int num = originLength-originStr.length();
		StringBuilder sb = new StringBuilder();
		for(int i=0;i<num+1;i++){
			sb.append("*");
		}
		originStr = originStr.replaceAll("~",sb.toString());
		return originStr;
	}
	public ResultCell[][] getData() {
		return data;
	}
	public void setData(ResultCell[][] data) {
		this.data = data;
	}
}
